package com.ak.game.service;

import com.ak.game.entity.PnGame;
import com.ak.game.entity.PnGameTwistRecord;
import com.ak.game.entity.PnVipUser;
import com.ak.game.entity.vo.BetReqVo;
import com.ak.game.util.AjaxResult;
import com.ak.game.util.CommonUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

@Service
public class BettingService {

    @Autowired
    private PnGameService gameService;

    @Autowired
    private PnGameTwistRecordService gameTwistRecordService;

    @Autowired
    private PnVipUserService vipUserService;

    @Value("${game.id}")
    private String gameId;

    /**
     * 赔率
     */
    public static Map<Integer, BigDecimal[]> ODDS = new HashMap<>();

    /**
     * 杀率
     */
    public Double winRate;

    /**
     * 虚拟账户胜率
     */
    private Integer tryOutRate;

    public static Map<String, ChannelHandlerContext> USER_CTX_MAP = new HashMap<>();

    @PostConstruct
    public void initOdds() {
        ODDS.clear();
        PnGame pnGame = gameService.getPnGame();
        String config = pnGame.getConfig();
        JSONObject jsonObject = JSONObject.parseObject(config);
        tryOutRate = jsonObject.getInteger("tryOutRate");
        ODDS.put(1, new BigDecimal[]{jsonObject.getList("1", BigDecimal.class).get(0), jsonObject.getList("1", BigDecimal.class).get(1), jsonObject.getList("1", BigDecimal.class).get(2), jsonObject.getBigDecimal("bonus1")});
        ODDS.put(2, new BigDecimal[]{jsonObject.getList("2", BigDecimal.class).get(0), jsonObject.getList("2", BigDecimal.class).get(1), jsonObject.getList("2", BigDecimal.class).get(2), jsonObject.getList("2", BigDecimal.class).get(3), jsonObject.getList("2", BigDecimal.class).get(4), jsonObject.getBigDecimal("bonus2")});
        ODDS.put(3, new BigDecimal[]{jsonObject.getList("3", BigDecimal.class).get(0), jsonObject.getList("3", BigDecimal.class).get(1), jsonObject.getList("3", BigDecimal.class).get(2), jsonObject.getList("3", BigDecimal.class).get(3), jsonObject.getList("3", BigDecimal.class).get(4), jsonObject.getList("3", BigDecimal.class).get(5), jsonObject.getList("3", BigDecimal.class).get(6), jsonObject.getBigDecimal("bonus3")});
    }

    @PostConstruct
    public void initWinRate() {
        PnGame pnGame = gameService.getPnGame();
        winRate = pnGame.getWinRate();
    }

    private final Random random = new Random();

    public List<PnGameTwistRecord> selectAllTwistRecord(BetReqVo betReqVo) {
        // 数据处理
        String userId = betReqVo.getData().get("user_id").toString();
        LambdaQueryWrapper<PnGameTwistRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PnGameTwistRecord::getUserId, userId);
        queryWrapper.eq(PnGameTwistRecord::getGameId, gameId);
        queryWrapper.eq(PnGameTwistRecord::getIsOver, "1");
        return gameTwistRecordService.getBaseMapper().selectList(queryWrapper);
    }

    /**
     * 下注的方法
     *
     * @param betReqVo
     */
    @Transactional
    public Integer bet(BetReqVo betReqVo) {
        // 数据处理
        String userId = betReqVo.getData().get("user_id").toString();
        PnVipUser vipUser = vipUserService.getById(userId);
        int result = random.nextInt(100);
        int flag = 0;
        BigDecimal multiple = BigDecimal.ZERO;
        if (vipUser.getSysUser() == 0) {
            if (result < (8 * winRate)) { // 0-8则是蓝色宝石
                multiple = ODDS.get(3)[0];
                flag = 3;
            } else if (result < (20 * winRate)) { // 8-20则是红色宝石
                multiple = ODDS.get(2)[0];
                flag = 2;
            } else if (result < (35 * winRate)) { // 20-35则是绿色宝石
                multiple = ODDS.get(1)[0];
                flag = 1;
            } else if (result < (65 * winRate)) { // 35-60则是无用宝石
                flag = 4;
            } else { // 60-100则是烂石头
                flag = 5;
            }
        } else {
            if (result < (25 * tryOutRate / 100)) { // 0-8则是蓝色宝石
                multiple = ODDS.get(3)[0];
                flag = 3;
            } else if (result < (40 * tryOutRate / 100)) { // 8-20则是红色宝石
                multiple = ODDS.get(2)[0];
                flag = 2;
            } else if (result < (75 * tryOutRate / 100)) { // 20-35则是绿色宝石
                multiple = ODDS.get(1)[0];
                flag = 1;
            } else if (result < (95 * tryOutRate / 100)) { // 35-60则是无用宝石
                flag = 4;
            } else { // 60-100则是烂石头
                flag = 5;
            }
        }

        // 查询pn_game_twist_record表用户的下注记录
        LambdaQueryWrapper<PnGameTwistRecord> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PnGameTwistRecord::getUserId, userId);
        queryWrapper.eq(PnGameTwistRecord::getGameId, gameId);
        queryWrapper.eq(PnGameTwistRecord::getIsOver, "1");
        queryWrapper.eq(PnGameTwistRecord::getSysSelect, flag);
        queryWrapper.orderByDesc(PnGameTwistRecord::getMultiple);
        queryWrapper.last("limit 1");
        PnGameTwistRecord gameTwistRecord = gameTwistRecordService.getOne(queryWrapper);

        // 如果gameTwistRecord不为null，证明此玩家之前有过这个赔率
        if (ObjectUtils.isNotNull(gameTwistRecord)) {
            int index = 0;
            if (flag == 1) {
                if (gameTwistRecord.getMultiple().compareTo(ODDS.get(1)[0]) == 0) {
                    index = 0;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(1)[1].subtract(ODDS.get(1)[0])) == 0) {
                    index = 1;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(1)[2].subtract(ODDS.get(1)[1])) == 0) {
                    index = 2;
                }
            } else if (flag == 2) {
                if (gameTwistRecord.getMultiple().compareTo(ODDS.get(2)[0]) == 0) {
                    index = 0;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(2)[1].subtract(ODDS.get(2)[0])) == 0) {
                    index = 1;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(2)[2].subtract(ODDS.get(2)[1])) == 0) {
                    index = 2;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(2)[3].subtract(ODDS.get(2)[2])) == 0) {
                    index = 3;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(2)[4].subtract(ODDS.get(2)[3])) == 0) {
                    index = 4;
                }
            } else if (flag == 3) {
                if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[0]) == 0) {
                    index = 0;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[1].subtract(ODDS.get(3)[0])) == 0) {
                    index = 1;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[2].subtract(ODDS.get(3)[1])) == 0) {
                    index = 2;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[3].subtract(ODDS.get(3)[2])) == 0) {
                    index = 3;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[4].subtract(ODDS.get(3)[3])) == 0) {
                    index = 4;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[5].subtract(ODDS.get(3)[4])) == 0) {
                    index = 5;
                } else if (gameTwistRecord.getMultiple().compareTo(ODDS.get(3)[6].subtract(ODDS.get(3)[5])) == 0) {
                    index = 6;
                }
            }
            BigDecimal multipleNow = ODDS.get(flag)[index + 1].subtract(ODDS.get(flag)[index]);
            BigDecimal win = BigDecimal.ZERO;
            if (flag == 1 && index == 2) {
                // 绿色赔率顶满了，立即兑现奖励
                multipleNow = ODDS.get(1)[3];
                win = new BigDecimal(betReqVo.getData().get("amount").toString()).multiply(multipleNow);
                Map<String, Object> data = Map.of("user_id", userId, "win", win, "amount", betReqVo.getData().get("amount"));
                Map<String, Object> resultReqVo = Map.of("data", data, "game", betReqVo.getGame(), "msg_id", "110");
                try {
                    boolean response = true;
                    do {
                        response = Boolean.parseBoolean(RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS).toString());
                    } while (!response);
                } catch (InterruptedException | TimeoutException | ExecutionException e) {
                    throw new RuntimeException(e);
                }
            } else if (flag == 2 && index == 4) {
                // 绿色赔率顶满了，立即兑现奖励
                multipleNow = ODDS.get(2)[5];
                win = new BigDecimal(betReqVo.getData().get("amount").toString()).multiply(multipleNow);
                Map<String, Object> data = Map.of("user_id", userId, "win", win, "amount", betReqVo.getData().get("amount"));
                Map<String, Object> resultReqVo = Map.of("data", data, "game", betReqVo.getGame(), "msg_id", "110");
                try {
                    boolean response = true;
                    do {
                        response = Boolean.parseBoolean(RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS).toString());
                    } while (!response);
                } catch (InterruptedException | TimeoutException | ExecutionException e) {
                    throw new RuntimeException(e);
                }
            } else if (flag == 3 && index == 6) {
                // 蓝色赔率顶满了，立即兑现奖励
                multipleNow = ODDS.get(3)[7];
                win = new BigDecimal(betReqVo.getData().get("amount").toString()).multiply(multipleNow);
                Map<String, Object> data = Map.of("user_id", userId, "win", win, "amount", betReqVo.getData().get("amount"));
                Map<String, Object> resultReqVo = Map.of("data", data, "game", betReqVo.getGame(), "msg_id", "110");
                try {
                    boolean response = true;
                    do {
                        response = Boolean.parseBoolean(RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS).toString());
                    } while (!response);
                } catch (InterruptedException | TimeoutException | ExecutionException e) {
                    throw new RuntimeException(e);
                }
            }
            PnGameTwistRecord pnGameTwistRecord = new PnGameTwistRecord();
            pnGameTwistRecord.setGameId(gameId);
            pnGameTwistRecord.setUserId(userId);
            pnGameTwistRecord.setRecordId(betReqVo.getGame().get("round_id").toString());
            pnGameTwistRecord.setPlaysessionId(gameId + betReqVo.getGame().get("round_id") + vipUser.getBinding());
            pnGameTwistRecord.setStartTime(CommonUtil.formatLong2Date(betReqVo.getGame().get("start_time").toString()));
            pnGameTwistRecord.setTimestamp(betReqVo.getGame().get("round_id").toString());
            pnGameTwistRecord.setEndTime(CommonUtil.formatLong2Date(System.currentTimeMillis()));
            pnGameTwistRecord.setAmount(new BigDecimal(betReqVo.getData().get("amount").toString()));
            pnGameTwistRecord.setWin(win);
            pnGameTwistRecord.setMultiple(multipleNow);
            pnGameTwistRecord.setItemStr(JSON.toJSONString(betReqVo));
            pnGameTwistRecord.setSysSelect(String.valueOf(flag));
            if (win.compareTo(BigDecimal.ZERO) == 0) {
                pnGameTwistRecord.setIsCash("1");
                pnGameTwistRecord.setIsOver("1");
            } else {
                pnGameTwistRecord.setIsCash("0");
                pnGameTwistRecord.setIsOver("0");
            }

            gameTwistRecordService.save(pnGameTwistRecord);
        } else { // 没查出来数据证明，之前没有这条赔率，则保存这条数据
            // 开奖结果为无用宝石or烂石头
            if (flag > 3) {
                PnGameTwistRecord pnGameTwistRecord = new PnGameTwistRecord();
                pnGameTwistRecord.setGameId(gameId);
                pnGameTwistRecord.setUserId(userId);
                pnGameTwistRecord.setRecordId(betReqVo.getGame().get("round_id").toString());
                pnGameTwistRecord.setPlaysessionId(gameId + betReqVo.getGame().get("round_id") + vipUser.getBinding());
                pnGameTwistRecord.setStartTime(CommonUtil.formatLong2Date(betReqVo.getGame().get("start_time").toString()));
                pnGameTwistRecord.setTimestamp(betReqVo.getGame().get("round_id").toString());
                pnGameTwistRecord.setEndTime(CommonUtil.formatLong2Date(System.currentTimeMillis()));
                pnGameTwistRecord.setAmount(new BigDecimal(betReqVo.getData().get("amount").toString()));
                pnGameTwistRecord.setWin(BigDecimal.ZERO);
                pnGameTwistRecord.setMultiple(multiple);
                pnGameTwistRecord.setItemStr(JSON.toJSONString(betReqVo));
                pnGameTwistRecord.setSysSelect(String.valueOf(flag));
                pnGameTwistRecord.setIsCash("1");
                pnGameTwistRecord.setIsOver("0");
                gameTwistRecordService.save(pnGameTwistRecord);
                // 开奖结果为烂石头，则需要处理之前的赔率，查询到之前的投注记录，并且退回一格
                if (flag == 5) {
                    // 查询之前还未结算的投注记录
                    LambdaQueryWrapper<PnGameTwistRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
                    lambdaQueryWrapper.eq(PnGameTwistRecord::getGameId, gameId);
                    lambdaQueryWrapper.eq(PnGameTwistRecord::getUserId, userId);
                    lambdaQueryWrapper.eq(PnGameTwistRecord::getIsOver, "1");
                    List<PnGameTwistRecord> pnGameTwistRecords = gameTwistRecordService.getBaseMapper().selectList(lambdaQueryWrapper);
                    Map<String, List<PnGameTwistRecord>> groupedRecords = pnGameTwistRecords.stream().collect(Collectors.groupingBy(PnGameTwistRecord::getSysSelect, // 按 sysSelect 分组
                                    Collectors.toList() // 先收集为 List
                            )).entrySet().stream() // 转换为 Entry Stream
                            .collect(Collectors.toMap( // 再次收集为 Map
                                    Map.Entry::getKey, // key 保持不变
                                    entry -> entry.getValue().stream() // 对每个 List 进行排序
                                            .sorted(Comparator.comparing(PnGameTwistRecord::getMultiple).reversed()).collect(Collectors.toList())));
                    for (Map.Entry<String, List<PnGameTwistRecord>> stringListEntry : groupedRecords.entrySet()) {
                        PnGameTwistRecord gameTwistRecord1 = stringListEntry.getValue().get(0);
                        gameTwistRecord1.setWin(BigDecimal.ZERO);
                        gameTwistRecord1.setIsOver("0");
                        gameTwistRecordService.updateById(gameTwistRecord1);
                        Map<String, Object> data = Map.of("user_id", userId, "win", BigDecimal.ZERO, "amount", betReqVo.getData().get("amount"));
                        Map<String, Object> game = Map.of("id", gameId, "round_id", gameTwistRecord1.getRecordId(), "start_time", gameTwistRecord1.getTimestamp());
                        Map<String, Object> resultReqVo = Map.of("data", data, "game", game, "msg_id", "110");
                        try {
                            RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS);
                        } catch (InterruptedException | ExecutionException | TimeoutException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
                Map<String, Object> data = Map.of("user_id", userId, "win", BigDecimal.ZERO, "amount", betReqVo.getData().get("amount"));
                Map<String, Object> resultReqVo = Map.of("data", data, "game", betReqVo.getGame(), "msg_id", "110");
                try {
                    RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS);
                } catch (InterruptedException | ExecutionException | TimeoutException e) {
                    throw new RuntimeException(e);
                }
            } else { // 开奖结果为宝石
                PnGameTwistRecord pnGameTwistRecord = new PnGameTwistRecord();
                pnGameTwistRecord.setGameId(gameId);
                pnGameTwistRecord.setUserId(userId);
                pnGameTwistRecord.setRecordId(betReqVo.getGame().get("round_id").toString());
                pnGameTwistRecord.setPlaysessionId(gameId + betReqVo.getGame().get("round_id") + vipUser.getBinding());
                pnGameTwistRecord.setStartTime(CommonUtil.formatLong2Date(betReqVo.getGame().get("start_time").toString()));
                pnGameTwistRecord.setTimestamp(betReqVo.getGame().get("round_id").toString());
                pnGameTwistRecord.setEndTime(CommonUtil.formatLong2Date(System.currentTimeMillis()));
                pnGameTwistRecord.setAmount(new BigDecimal(betReqVo.getData().get("amount").toString()));
                pnGameTwistRecord.setWin(BigDecimal.ZERO);
                pnGameTwistRecord.setMultiple(multiple);
                pnGameTwistRecord.setItemStr(JSON.toJSONString(betReqVo));
                pnGameTwistRecord.setSysSelect(String.valueOf(flag));
                pnGameTwistRecord.setIsCash("1");
                pnGameTwistRecord.setIsOver("1");
                gameTwistRecordService.save(pnGameTwistRecord);
            }
        }
        return flag;
    }

    public void cashPartial(String userId) {
        LambdaQueryWrapper<PnGameTwistRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PnGameTwistRecord::getGameId, gameId);
        lambdaQueryWrapper.eq(PnGameTwistRecord::getUserId, userId);
        lambdaQueryWrapper.eq(PnGameTwistRecord::getIsOver, "1");
        List<PnGameTwistRecord> pnGameTwistRecords = gameTwistRecordService.getBaseMapper().selectList(lambdaQueryWrapper);
        Map<String, List<PnGameTwistRecord>> groupedRecords = pnGameTwistRecords.stream().collect(Collectors.groupingBy(PnGameTwistRecord::getSysSelect, // 按 sysSelect 分组
                        Collectors.toList() // 先收集为 List
                )).entrySet().stream() // 转换为 Entry Stream
                .collect(Collectors.toMap( // 再次收集为 Map
                        Map.Entry::getKey, // key 保持不变
                        entry -> entry.getValue().stream() // 对每个 List 进行排序
                                .sorted(Comparator.comparing(PnGameTwistRecord::getMultiple).reversed()).collect(Collectors.toList())));
        System.out.println(groupedRecords);
        for (Map.Entry<String, List<PnGameTwistRecord>> stringListEntry : groupedRecords.entrySet()) {
            PnGameTwistRecord gameTwistRecord = stringListEntry.getValue().get(0);
            gameTwistRecord.setWin(gameTwistRecord.getMultiple().multiply(gameTwistRecord.getAmount()));
            gameTwistRecord.setIsCash("0");
            gameTwistRecord.setIsOver("0");
            gameTwistRecordService.updateById(gameTwistRecord);
            Map<String, Object> data = Map.of("user_id", userId, "win", gameTwistRecord.getWin(), "amount", gameTwistRecord.getAmount());
            Map<String, Object> game = Map.of("id", gameId, "start_time", gameTwistRecord.getTimestamp(), "end_time", System.currentTimeMillis(), "round_id", gameTwistRecord.getRecordId());
            Map<String, Object> resultReqVo = Map.of("data", data, "game", game, "msg_id", "110");
            try {
                boolean response = true;
                do {
                    response = Boolean.parseBoolean(RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS).toString());
                } while (!response);
            } catch (InterruptedException | TimeoutException | ExecutionException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void cashAll(String userId) {
        LambdaQueryWrapper<PnGameTwistRecord> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PnGameTwistRecord::getGameId, gameId);
        lambdaQueryWrapper.eq(PnGameTwistRecord::getUserId, userId);
        lambdaQueryWrapper.eq(PnGameTwistRecord::getIsOver, "1");
        List<PnGameTwistRecord> pnGameTwistRecords = gameTwistRecordService.getBaseMapper().selectList(lambdaQueryWrapper);
        Map<String, List<PnGameTwistRecord>> groupedRecords = pnGameTwistRecords.stream().collect(Collectors.groupingBy(PnGameTwistRecord::getSysSelect, // 按 sysSelect 分组
                        Collectors.toList() // 先收集为 List
                )).entrySet().stream() // 转换为 Entry Stream
                .collect(Collectors.toMap( // 再次收集为 Map
                        Map.Entry::getKey, // key 保持不变
                        entry -> entry.getValue().stream() // 对每个 List 进行排序
                                .sorted(Comparator.comparing(PnGameTwistRecord::getMultiple).reversed()).collect(Collectors.toList())));
        System.out.println(groupedRecords);
        for (Map.Entry<String, List<PnGameTwistRecord>> stringListEntry : groupedRecords.entrySet()) {
            for (PnGameTwistRecord gameTwistRecord : stringListEntry.getValue()) {
                gameTwistRecord.setWin(gameTwistRecord.getMultiple().multiply(gameTwistRecord.getAmount()));
                gameTwistRecord.setIsCash("0");
                gameTwistRecord.setIsOver("0");
                gameTwistRecordService.updateById(gameTwistRecord);
                Map<String, Object> data = Map.of("user_id", userId, "win", gameTwistRecord.getWin(), "amount", gameTwistRecord.getAmount());
                Map<String, Object> game = Map.of("id", gameId, "start_time", gameTwistRecord.getTimestamp(), "end_time", System.currentTimeMillis(), "round_id", gameTwistRecord.getRecordId());
                Map<String, Object> resultReqVo = Map.of("data", data, "game", game, "msg_id", "110");
                try {
                    boolean response = true;
                    do {
                        response = Boolean.parseBoolean(RemoteWebSocketClientService.sendMessage(JSON.toJSONString(resultReqVo)).get(10, TimeUnit.SECONDS).toString());
                    } while (!response);
                } catch (InterruptedException | TimeoutException | ExecutionException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    public void flushConfig() {
        // 获取新的游戏配置
        initOdds();
        // 返回到1分钟游戏场
        for (Map.Entry<String, ChannelHandlerContext> item : USER_CTX_MAP.entrySet()) {
            item.getValue().channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(AjaxResult.success(ODDS, "1004"))));
        }
    }

    public void flushWinRate() {
        // 获取新的游戏配置
        initWinRate();
    }
}
